﻿/*******************************************************************************
 **  Name:                                        **
 **  Description:                                                             **
 **                                                                           **
 **  CDDL: Open Source Initiative (OSI) Approved License                            **
 **                                                                           **
 **  Copyright (c) 2009-2010 Barry "Gian" James  <bjames@munixos.net>         **
 **  All rights reserved.                                                     **
 **                                                                           **
 **  The contents of this file are subject to the terms of the CDDL:          **
 **  Common Development and Distribution License (the "License").             **
 **  You may not use this file except in compliance with the License.         **
 **                                                                           **
 **  You can obtain a copy of the license at $PROJECT_ROOT/LICENSE            **
 **  or http://www.opensolaris.org/os/licensing.  This code is Open Source    **
 **  and you are free to use it within the confines of the license, even      **
 **  for your own closed-source commercial projects, as long as you follow    **
 **  the terms set forth in the CDDL.                                         **
 **                                                                           **
 **  When distributing Covered Code, include this CDDL HEADER in each         **
 **  file and include the License file at $PROJECT_ROOT/LICENSE.              **
 **  If applicable, add the following below this CDDL HEADER, with the        **
 **  fields enclosed by brackets "[]" replaced with your own identifying      **
 **  information: Portions Copyright [yyyy] [name of copyright owner]         **
 **                                                                           **
 ******************************************************************************/
// Created on November 1, 2010, 7:25 AM
// Modified $Date$ by $Author$
// $Id$

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Net;
using System.Net.Sockets;
using System.IO;
using System.Threading;

namespace sat1baf1
{
	public partial class MainForm : Form
	{
		// Form methods
		public MainForm()
		{
			InitializeComponent();
			ServerIPTextBox.Text = GetIP();
			ServerPortTextBox.Text = DEFAULT_PORT;

		}
		protected override void OnLoad(System.EventArgs ev)
		{
			base.OnLoad(ev);
			CURR_DIR = Directory.GetCurrentDirectory();
			// Maybe change these to XML at some point?  nah...
			WeaponQualities = new WeaponQualityList();
			NumWeaponQualities = WeaponQualities.LoadFile();
			weaponsizes = new WeaponSizeList();
			weaponsizes.LoadFile();
			toolStripStatusText.Text = "Loaded " + NumWeaponQualities.ToString() + " Weapon Qualities";
			for (int i = 0; i < MAX_CLIENTS; i++)
			{
				m_AgentSockets[i] = new AgentSock();
				m_AgentSockets[i].agent = string.Empty;
				m_AgentSockets[i].cmdArgs = string.Empty;
				m_AgentSockets[i].IsConnected = false;
				m_AgentSockets[i].sock = null;
			}
		}

		const int MAX_CLIENTS = 10;
		const string DEFAULT_PORT = "8030";
		const string DEFAULT_WEAPONDB = "Weapons.xml";
		const string DEFAULT_AGENTDB = "Agents.xml";
		private string CURR_DIR = string.Empty;

		private WeaponQualityList wpnQualities;
		private WeaponSizeList wpnsizes;
		private int NumWeaponQualities = 0;
		private Socket m_mainSocket;            // This is the socket we bind and listen to
		public struct AgentSock
		{
			public Socket sock;
			public string agent;
			public string cmdArgs;
			public bool IsConnected;
			public int idx;
		}              // The structure encapsulating the socket an agent is connected to
		public AgentSock[] m_AgentSockets = new AgentSock[MAX_CLIENTS]; // All our connected agents

		private int m_clientCount = 0;
		delegate void SetTextCallback(string text);
		delegate void RemoveClientFromListCallback(string text);


		public WeaponQualityList WeaponQualities { get { return wpnQualities; } set { wpnQualities = value; } }
		public WeaponSizeList weaponsizes { get { return wpnsizes; } set { wpnsizes = value; } }
		public WeaponSize[] WeaponSizes { get { return weaponsizes.GetList; } }
	
  
		public void DisconnectFromServer(int idx)
		{
			XmlLog.Instance.Add("MainForm:DisconnectFromServer(): Disconnecting " + m_AgentSockets[idx].agent);
 //           sp.m_currentSocket.Disconnect(true);
			while (m_AgentSockets[idx].IsConnected != false)
			{
				//lock (sp)
				//{
				RemoveClientFromList(m_AgentSockets[idx].agent);
				m_AgentSockets[idx].sock.Disconnect(true);
				m_AgentSockets[idx].IsConnected = false;
				//}
			}
		}
		private void OnClientConnectBanner(Socket s)
		{
			Object objData = "Connecting...done\r\nInitiating firewall slingshot...successful!\r\nExecutive Defense Directorate Remote Access v5.72a\r\nCovert Field Operations Division\r\n";
			byte[] byData = System.Text.Encoding.ASCII.GetBytes(objData.ToString());
			s.Send(byData);
			objData = "Negotiating 2048-bit strong encryption handshake.\r\nUnauthorized access to this server is a federal offense.\r\nAll connections are logged.\r\n\n";
			byData = System.Text.Encoding.ASCII.GetBytes(objData.ToString());
			s.Send(byData);
			objData = "EXECUTIVE DEFENSE DIRECTORATE\r\n";
			byData = System.Text.Encoding.ASCII.GetBytes(objData.ToString());
			s.Send(byData);

		}
		private bool  DoLogin(AgentSock s)
		{
			byte[] byData = new byte[25];
			int ct = 0;
			StringBuilder sb = new StringBuilder();
			string uname = "";
			string passwd = "";

			for (int i = 0; i < 3; i++)
			{
				byData = System.Text.Encoding.ASCII.GetBytes("Login: ");
				s.sock.Send(byData);

				ct = s.sock.Receive(byData);
				while (ct > 0) {
					sb.Append(Encoding.ASCII.GetString(byData, 0, ct));
					ct = s.sock.Receive(byData);
					if (Encoding.ASCII.GetString(byData).Contains("\n")) {
						uname = sb.ToString();
 //                       MessageBox.Show("Username: " + uname);
						break;
					}
				}

				byData = System.Text.Encoding.ASCII.GetBytes("Password: ");
				s.sock.Send(byData);
				sb.Remove(0, sb.Length);
				ct = s.sock.Receive(byData);
				while (ct > 0)
				{
					sb.Append(Encoding.ASCII.GetString(byData, 0, ct));
					ct = s.sock.Receive(byData);
					if (Encoding.ASCII.GetString(byData).Contains("\n"))
					{
						passwd = sb.ToString();
  //                      MessageBox.Show("Password: " + passwd);

						break;
					}
				}

				// TODO: FORMAL USER/PASSWD CHECK HERE
				if (passwd == "newlife8")
				{
					byData = System.Text.Encoding.ASCII.GetBytes("OK.\r\n\r\n? ");
					s.sock.Send(byData);
					return true;
				}
				sb.Remove(0, sb.Length);

			}
			s.sock.Close();
			s.sock = null;
			return false;
		}


 

		// Network methods
		//// Establish connections
		private void Listen()
		{
			// Start listening...
			m_mainSocket.Listen(MAX_CLIENTS);
			while (true)
			{
				m_AgentSockets[m_clientCount].sock = m_mainSocket.Accept();
				m_AgentSockets[m_clientCount].cmdArgs = "LOGIN";

				// Fork off a thread to handle each connection
				Thread clientThread = new Thread(DoNewConnection);
				clientThread.Start(m_AgentSockets[m_clientCount]);
				m_clientCount++;
			}

		}
		/// <summary>
		/// Top-level thread function to process new connections.
		/// </summary>
		/// <param name="s">Index into m_AgentSockets[] for this connection</param>
		private void DoNewConnection(Object s)
		{
			AgentSock agentSock = (AgentSock)s;
			OnClientConnectBanner(agentSock.sock);
			bool isOK = DoLogin(agentSock);
			while (agentSock.IsConnected)
			{
				// Block while waiting on data from agent socket
			}

		}

		//// Helper methods
		void CloseSockets()
	   {
			if(m_mainSocket != null){
				m_mainSocket.Close();
			}
			for(int i = 0; i < m_clientCount; i++){
				if(m_AgentSockets[i].sock != null){
					m_AgentSockets[i].sock.Close();
					m_AgentSockets[i].sock = null;
				}
			}	
	   }
		String GetIP()
		{
			string strHostName = Dns.GetHostName();

			// Find host by name
			IPHostEntry iphostentry = Dns.GetHostEntry(strHostName);
			

			// Grab the first IP addresses
			String IPStr = "";
			foreach (IPAddress ipaddress in iphostentry.AddressList)
			{
				IPStr = ipaddress.ToString();
				MessageBox.Show(strHostName);
				toolStripStatusLabel1.Text = ipaddress.AddressFamily.ToString();
				return IPStr;
			}
			return IPStr;
		}
 

		// Start and Stop the server
		private void StopServerBtn_Click(object sender, EventArgs e)
		{
			CloseSockets();
			UpdateControls(false);
		}
		private void StartServerBtn_Click(object sender, EventArgs e)
		{
			try
			{   
				//toolStripStatusText.Text = "Loaded " + NumWeaponQualities.ToString() + " Weapon Qualities";

				// Check the port value
				if (ServerPortTextBox.Text == "")
				{
					MessageBox.Show("Please enter a Port Number");
					return;
				}
				int port = System.Convert.ToInt32(ServerPortTextBox.Text);
				// Create the listening socket...
				m_mainSocket = new Socket(AddressFamily.InterNetwork,
										  SocketType.Stream,
										  ProtocolType.Tcp);
				IPEndPoint ipLocal = new IPEndPoint(IPAddress.Any, port);
				// Bind to local IP Address...
				m_mainSocket.Bind(ipLocal);
				// One thread to rule them all...
				// Here we create a thread to start listening and blocking
				Thread listenThread = new Thread(new ThreadStart(Listen));
				listenThread.Start();



				UpdateControls(true);

			}
			catch (SocketException se)
			{
				MessageBox.Show(se.Message);
			}

		}

		// GUI hooks
		private void UpdateControls(bool listening)
		{
			StartServerBtn.Enabled = !listening;
			ServerIPTextBox.Enabled = !listening;
			ServerPortTextBox.Enabled = !listening;
			StopServerBtn.Enabled = listening;
			ClientsListBox.Items.Clear();
		}
		public void SetText(string text)
		{
			// InvokeRequired required compares the thread ID of the
			// calling thread to the thread ID of the creating thread.
			// If these threads are different, it returns true.
			if (this.RxListBox.InvokeRequired)
			{
				SetTextCallback d = new SetTextCallback(SetText);
				this.Invoke(d, new object[] { text });
			}
			else
			{
				this.RxListBox.Items.Add(text);
			}
		}
		private void SetClientListBox(string text)
		{
			// InvokeRequired required compares the thread ID of the
			// calling thread to the thread ID of the creating thread.
			// If these threads are different, it returns true.
			if (this.RxListBox.InvokeRequired)
			{
				SetTextCallback d = new SetTextCallback(SetClientListBox);
				this.Invoke(d, new object[] { text });
			}
			else
			{
				this.ClientsListBox.Items.Add(text);
			}
		}
		public void RemoveClientFromList(string text)
		{
			foreach (var v in this.ClientsListBox.Items)
			{
				XmlLog.Instance.Add("MainForm:RemoveClientFromList(): " + text + " vs " + v);
				if (text == v)
				{
					// InvokeRequired required compares the thread ID of the
					// calling thread to the thread ID of the creating thread.
					// If these threads are different, it returns true.
					if (this.RxListBox.InvokeRequired)
					{
						RemoveClientFromListCallback d = new RemoveClientFromListCallback(RemoveClientFromList);
						this.Invoke(d, new object[] { text });
					}
					else
					{
						this.ClientsListBox.Items.Remove(v);
					}
					break;
				}


				
			}

		}
		private void weaponQualitiesToolStripMenuItem_Click(object sender, EventArgs e)
		{
			WeaponQualityForm form = new WeaponQualityForm(this);
			form.Show();
		}
		private void weaponSizesT513ToolStripMenuItem_Click(object sender, EventArgs e)
		{
			WeaponSizeForm form = new WeaponSizeForm(this);
			form.Show();
		}
		private void weaponsToolStripMenuItem_Click(object sender, EventArgs e)
		{
			WeaponInventoryForm form = new WeaponInventoryForm(this);
			form.Show();
		}
		private void agentAdministrationToolStripMenuItem_Click(object sender, EventArgs e)
		{
			AgentListForm form = new AgentListForm();
			form.Show();
		}
		private void agencyInformationToolStripMenuItem_Click(object sender, EventArgs e)
		{
			AgencyForm form = new AgencyForm();
			form.Show();
		}
		private void newAgentBuilderToolStripMenuItem_Click(object sender, EventArgs e)
		{
			CharacterCreatorForm form = new CharacterCreatorForm();
			form.Show();
		}
		private void missionCatalogToolStripMenuItem_Click(object sender, EventArgs e)
		{
			MissionCatalogForm form = new MissionCatalogForm();
			form.Show();
		}
		private void missionBuilderToolStripMenuItem1_Click(object sender, EventArgs e)
		{
			NewMissionForm form = new NewMissionForm();
			form.Show();
		}
		private void exitToolStripMenuItem_Click(object sender, EventArgs e)
		{
			CloseSockets();
			Close();
		}


	}


}
// Outdated functions kept here for posterity and reference

		// This is the call back function, which will be invoked when a client is connected
		//public void OnClientConnect(IAsyncResult asyn)
		//{
		//    try
		//    {
		//        // Here we complete/end the BeginAccept() asynchronous call
		//        // by calling EndAccept() - which returns the reference to
		//        // a new Socket object
		//        m_workingSocket[m_clientCount].m_workerSocket = m_mainSocket.EndAccept(asyn);
		//        m_workingSocket[m_clientCount].agent = "<UNKOWN_AGENT>";
		//        m_workingSocket[m_clientCount].Cmd = 0; // login command
		//        m_workingSocket[m_clientCount].idx = m_clientCount;
		//        m_workingSocket[m_clientCount].Connected = true;



		//        //////////////////////////////////////////////////////////////////////////////// LOGIN
		//        // banner
		//        OnClientConnectBanner(m_clientCount);
		//        string un = m_workingSocket[m_clientCount].agent = DoLogin(m_workingSocket[m_clientCount]);
		//        SetClientListBox(un);
		//        ////////////////////////////////////////////////////////////////////////////////////////////


		//        // Let the worker Socket do the further processing for the 
		//        // just connected client
		//        WaitForData(m_workingSocket[m_clientCount].m_workerSocket, m_clientCount);
		//        // Now increment the client count
		//        ++m_clientCount;
		//        // Display this client connection as a status message on the GUI	
		//        String str = String.Format("Client # {0} connected", m_clientCount);
		//        toolStripStatusText.Text = str;


		//        // Since the main Socket is now free, it can go back and wait for
		//        // other clients who are attempting to connect
		//        m_mainSocket.BeginAccept(new AsyncCallback(OnClientConnect), null);
		//    }
		//    catch (ObjectDisposedException)
		//    {
		//        System.Diagnostics.Debugger.Log(0, "1", "\n OnClientConnection: Socket has been closed\n");
		//    }
		//    catch (SocketException se)
		//    {
		//        MessageBox.Show(se.Message);
		//    }

		//}
		//public void OnClientDisconnect(IAsyncResult sync)
		//{
		   
		//}
		//public class SocketPacket
		//{
		//    public System.Net.Sockets.Socket m_currentSocket;
		//    public AgentSock m_currAgent;
		//    public const int buffsz = 256; 
		//    public byte[] dataBuffer = new byte[buffsz];
		//    public StringBuilder sb = new StringBuilder();
		//}

		// Start waiting for data from the client
		//public void WaitForData(System.Net.Sockets.Socket soc, int idx)
		//{
		//    try
		//    {
		//        if (pfnWorkerCallBack == null)
		//        {
		//            // Specify the call back function which is to be 
		//            // invoked when there is any write activity by the 
		//            // connected client
		//            pfnWorkerCallBack = new AsyncCallback(OnDataReceived);
		//        }
		//        SocketPacket theSocPkt = new SocketPacket();
		//        theSocPkt.m_currentSocket = soc;
		//        theSocPkt.m_currAgent = m_workingSocket[idx];

		//        // Start receiving any data written by the connected client
		//        // asynchronously
		//        soc.BeginReceive(theSocPkt.dataBuffer, 0,
		//                           SocketPacket.buffsz,
		//                           0,
		//                           pfnWorkerCallBack,
		//                           theSocPkt);
		//    }
		//    catch (SocketException se)
		//    {
		//        MessageBox.Show(se.Message);
		//    }

		//}
		//// This the call back function which will be invoked when the socket
		//// detects any client writing of data on the stream
		//public void OnDataReceived(IAsyncResult asyn)
		//{
		//    try
		//    {
		//        SocketPacket socketData = (SocketPacket)asyn.AsyncState;
				
		//        int iRx = 0;
		//        // Complete the BeginReceive() asynchronous call by EndReceive() method
		//        // which will return the number of characters written to the stream 
		//        // by the client
		//        iRx = socketData.m_currentSocket.EndReceive(asyn);


		//        if (Encoding.ASCII.GetString(socketData.dataBuffer).Contains("\n"))
		//        {
		//            if (socketData.sb.Length > 1 )
		//            {
		//                string sData = socketData.m_currAgent.agent + ": ";
		//                sData += socketData.sb.ToString();
		//                SetText(sData);

		//                // Process command
		//                CmdProc proc = new CmdProc(socketData);
		//                proc.Form = this;
		//                proc.Process();
						
		//            }                
		//            // Continue the waiting for data on the Socket
		//            WaitForData(socketData.m_currentSocket, socketData.m_currAgent.idx);
					
		//        }
				
		//        else if (iRx > 0)
		//        {
		//            socketData.sb.Append(Encoding.ASCII.GetString(socketData.dataBuffer, 0, iRx));
		//            //MessageBox.Show(socketData.sb.ToString());
		//            socketData.m_currentSocket.BeginReceive(socketData.dataBuffer, 0, SocketPacket.buffsz, 0,
		//                pfnWorkerCallBack, socketData);
		//        }

		//    }
		//    catch (ObjectDisposedException)
		//    {
		//        System.Diagnostics.Debugger.Log(0, "1", "\nOnDataReceived: Socket has been closed\n");
		//    }
		//    catch (SocketException se)
		//    {
		//        MessageBox.Show(se.Message);
		//    }
		//}
